/* out.c is part of VIP program
 * Written by J. Salvador Arias, 2010
 *      CONICET, INSUE, Instituto Miguel Lillo,
 *      Miguel Lillo 205, S.M. de Tucuman (4000)
 *      Tucuman, Argentina
 *      e-mail: jsalarias@csnat.unt.edu.ar
 *
 * VIP is a free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation and
 * Creative Commons.
 *
 * This file and the VIP program is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * To view a copy of this license, visit
 * http://creativecommons.org/licenses/GPL/2.0/
 * or send a letter to
 * Creative Commons, 171 Second Street, Suite 300,
 * San Francisco, California, 94105, USA.
 */

#include "out.h"
#include "grid.h"
#include <stdio.h>

static GString* DateString (gchar* date);
static void WriteNodeWithData (GNode* actNode, GString* outBuffer);

static void WritePhyloXMLTree (PHYLOTREE* tree, GString* outBuffer);
static void WriteCladoXMLTree (PHYLOTREE* tree, GString* outBuffer);

static void WriteKMLSingle (GNode* refNode, BITFIELD* outCells, SFLAG modeRecords, SFLAG modeRemoved, gchar* style,
                            GString* outBuffer);

static SCOUNTER CalculateRichness (INTARRAY* sppPerCell, INTARRAY* obsPerCell);
static SCOUNTER CalculatePD (INTARRAY* pdPerCell, INTARRAY* obsPerCell);

static gchar GetHexChar (SCOUNTER num);
static void WriteInHex (gchar* str, SCOUNTER num);

void WriteXMLFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navTree;
 GNode* navNode;
 GList* navGeo;
 GList* navName;
 PHYLONODE* node;
 PHYLOTREE* tree;
 GEOREF* geo;
 FILE* out;
 gchar* numStr;
 SCOUNTER c;

 iniLen = (85 * GETNUMSPP) + (65 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append (outBuffer, "\n\n<Vip>");
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   tree = (PHYLOTREE*) navTree -> data;
   g_string_append (outBuffer, "\n<Tree>");
   if (tree -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t<name>%s</name>", tree -> name);
   for (navNode = tree -> root; navNode != NULL; ) {
     UpdateOnCalculus ();
     node = (PHYLONODE*) navNode -> data;
     g_string_append_printf (outBuffer, "\n\t<Node id=\"%ld\">", node -> id);
     if (node -> name != NULL)
       g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", node -> name);
     if ((node -> minAge > 0) && (node -> minAge != NO_AGE))
       g_string_append_printf (outBuffer, "\n\t\t<age>%ld</age>", node -> minAge);
     if (g_node_first_child (navNode) != NULL) {
       navNode = g_node_first_child (navNode);
       continue;
     }
     for (c = 0; ; ++ c) {
       navName = g_list_nth (node -> term -> synonyms, c);
       if (navName == NULL) break;
       if (navName -> data == node -> term -> name) continue;
       g_string_append_printf (outBuffer, "\n\t\t<synonym>%s</synonym>", (gchar*) navName -> data);
     }
     for (navGeo = node -> term -> firstGeo; navGeo != NULL; navGeo = g_list_next (navGeo)) {
       UpdateOnCalculus ();
       geo = (GEOREF*) navGeo -> data;
       if (geo -> sp != node -> term -> list) break;
       g_string_append (outBuffer, "\n\t\t<SpecimenInfo>");
       if (geo -> name != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<name>%s</name>", geo -> name);
       if (geo -> collec != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<collection>%s</collection>", geo -> collec);
       if (geo -> catalog != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<catalogCode>%s</catalogCode>", geo -> catalog);
       if (geo -> url != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<url>%s</url>", geo -> url);
       if (geo -> reference != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<reference>%s</reference>", geo -> reference);
       if (geo -> identifier != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<identifiedBy>%s</identifiedBy>", geo -> identifier);
       if (geo -> sampleDate != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<collectionDate>%s</collectionDate>", geo -> sampleDate);
       if (geo -> collector != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\t<collector>%s</collector>", geo -> collector);
       g_string_append (outBuffer, "\n\t\t\t<Point>");
       g_string_append (outBuffer, "\n\t\t\t\t<coordinates>");
       numStr = g_strdup_printf ("%.6f", geo -> lon);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", geo -> lat);
       CheckRealStr (numStr);
       g_string_append (outBuffer, numStr);
       g_free (numStr);
       g_string_append (outBuffer, "</coordinates>");
       g_string_append (outBuffer, "\n\t\t\t</Point>\n\t\t</SpecimenInfo>");
     }
     while (navNode != NULL) {
       g_string_append (outBuffer, "\n\t</Node>");
       if (g_node_next_sibling (navNode) != NULL) {
         navNode = g_node_next_sibling (navNode);
         break;
       }
       navNode = navNode -> parent;
     }
   }
   g_string_append (outBuffer, "\n</Tree>");
 }
 g_string_append (outBuffer, "\n\n</Vip>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteKMLFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navTree;
 GNode* navNode;
 GList* navGeo;
 PHYLONODE* node;
 PHYLOTREE* tree;
 GEOREF* geo;
 FILE* out;
 gchar* numStr;
 GString* date;

 iniLen = (85 * GETNUMSPP) + (65 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\"?><kml xmlns=\"http://earth.google.com/kml/2.1\">");
 g_string_append (outBuffer, "\n\n<Document>");
 g_string_append_printf (outBuffer, "\n\t<name>%s</name>", fileName);
 g_string_append (outBuffer, "\n\t<description><![CDATA[<p>KML file generated by VIP (Arias, 2009)</p>");
 g_string_append (outBuffer, "\n\t\t<p>Useful links:<br>");
 g_string_append (outBuffer, "<a href=\"http://www.zmuc.dk/public/phylogeny/VIP\">");
 g_string_append (outBuffer, "www.zmuc.dk/public/phylogeny/VIP</a>: VIP download<br />");
 g_string_append (outBuffer, "\n\t\t<a href=\"mailto:sal.arias@gmail.com\">sal.arias@gmail.com</a>: ");
 g_string_append (outBuffer, "Salva e-mail</p>\n\t\t<p><b>Acknowledgment</b><br />Pablo, Claudia, ");
 g_string_append (outBuffer, "and Lolo, for suggestions and interest!</p>]]></description>\n");
 g_string_append (outBuffer, "\n");
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   tree = (PHYLOTREE*) navTree -> data;
   g_string_append (outBuffer, "\n");
   for (navNode = tree -> root; navNode != NULL; ) {
     UpdateOnCalculus ();
     node = (PHYLONODE*) navNode -> data;
     g_string_append_printf (outBuffer, "\n<Folder id=\"%ld\">", node -> id);
     if (node -> name != NULL)
       g_string_append_printf (outBuffer, "\n\t<name>%s</name>", node -> name);
     if (g_node_first_child (navNode) != NULL) {
       navNode = g_node_first_child (navNode);
       continue;
     }
     for (navGeo = node -> term -> firstGeo; navGeo != NULL; navGeo = g_list_next (navGeo)) {
       UpdateOnCalculus ();
       geo = (GEOREF*) navGeo -> data;
       if (geo -> sp != node -> term -> list) break;
       g_string_append (outBuffer, "\n\t<Placemark>");
       if (geo -> name != NULL)
         g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", geo -> name);
       g_string_append (outBuffer, "\n\t\t<description><![CDATA[<p>");
       if (geo -> name != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tTerminal: %s<br />", geo -> name);
       if (geo -> collec != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCollection: %s<br />", geo -> collec);
       if (geo -> catalog != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCatalogue code: %s <br />", geo -> catalog);
       if (geo -> url != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tUrl: <a hfer=\"%s\">%s</a><br />", geo -> url, geo -> url);
       if (geo -> reference != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tReference: %s<br />", geo -> reference);
       if (geo -> identifier != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tIdentified by: %s<br />", geo -> identifier);
       if (geo -> sampleDate != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCollection date: %s<br />", geo -> sampleDate);
       if (geo -> collector != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCollector: %s<br />", geo -> collector);
       g_string_append (outBuffer, "\n\t\t</p>]]></description>");
       if (geo -> sampleDate != NULL) {
         date = DateString (geo -> sampleDate);
         g_string_append (outBuffer, "\n\t\t<TimeStap>");
         g_string_append_printf (outBuffer, "\n\t\t\t<when>%s</when>", date -> str);
         g_string_append (outBuffer, "\n\t\t</TimeStap>");
         g_string_free (date, TRUE);
       }
       g_string_append (outBuffer, "\n\t\t<Point>");
       g_string_append (outBuffer, "\n\t\t\t<extrude>0</extrude>");
       g_string_append (outBuffer, "\n\t\t\t<altitudeMode>absolute</altitudeMode>");
       g_string_append (outBuffer, "\n\t\t\t<coordinates>");
       numStr = g_strdup_printf ("%.6f", geo -> lon);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", geo -> lat);
       CheckRealStr (numStr);
       g_string_append (outBuffer, numStr);
       g_free (numStr);
       g_string_append (outBuffer, "</coordinates>");
       g_string_append (outBuffer, "\n\t\t</Point>\n\t</Placemark>");
     }
     while (navNode != NULL) {
       g_string_append (outBuffer, "\n</Folder>");
       if (g_node_next_sibling (navNode) != NULL) {
         navNode = g_node_next_sibling (navNode);
         break;
       }
       navNode = navNode -> parent;
     }
   }
 }
 g_string_append (outBuffer, "\n\n</Document>\n</kml>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteVRXFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navTree;
 PHYLOTREE* tree;
 GPtrArray* recArray;
 FILE* out;
 SCOUNTER i;
 GList* navRec;
 RECONS* actRec;
 PHYLONODE* anc;

 iniLen = (85 * GETNUMSPP) + (65 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append (outBuffer, "\n\n<VipResults>");
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   tree = (PHYLOTREE*) navTree -> data;
   if (tree -> recs == NULL) continue;
   for (navRec = tree -> recs; navRec != NULL; navRec = g_list_next (navRec)) {
     UpdateOnCalculus ();
     g_string_append_printf (outBuffer,"\n\n<Reconstruction>\n\t<treeID>%ld</treeID>", tree -> id);
     recArray = (GPtrArray*) navRec -> data;
     for (i = 0; i < recArray -> len; ++ i) {
       actRec = (RECONS*) g_ptr_array_index (recArray, i);
       if (actRec -> nodeFlag & REMOV_NODE) {
         g_string_append_printf (outBuffer, "\n\t<DistroElimination>\n\t\t<nodeID>%ld</nodeID>\n\t</DistroElimination>",
                                 actRec -> node -> id);
       }
       if (actRec -> node -> node -> parent != NULL) {
         anc = (PHYLONODE*) actRec -> node -> node -> parent -> data;
         if (anc -> rec -> removSet == actRec -> node)
           g_string_append_printf (outBuffer, "\n\t<PartialElimination>\n\t\t<nodeID>%ld</nodeID>\n\t</PartialElimination>",
                                 actRec -> node -> id);
       }
     }
     g_string_append (outBuffer,"\n</Reconstruction>");
   }
 }
 g_string_append (outBuffer, "\n\n</VipResults>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteXYDFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navTerm;
 GList* navGeo;
 TERMINAL* actTerm;
 GEOREF* geo;
 FILE* out;
 SCOUNTER i;
 gchar* numStr;

 iniLen = (20 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append_printf (outBuffer, "\nspp %ld", GETNUMSPP);
 g_string_append (outBuffer, "\nynegative");
 g_string_append (outBuffer, "\nxydata");
 i = 0;
 for (navTerm = GETSPP; navTerm != NULL; navTerm = g_list_next (navTerm)) {
   actTerm = (TERMINAL*) navTerm -> data;
   if (actTerm -> name != NULL)
     g_string_append_printf (outBuffer, "\n\nsp %ld [%s]", i, actTerm -> name);
   else
     g_string_append_printf (outBuffer, "\n\nsp %ld [species_%ld]", i, i);
   ++ i;
   for (navGeo = actTerm -> firstGeo; navGeo != NULL; navGeo = g_list_next (navGeo)) {
     UpdateOnCalculus ();
     geo = (GEOREF*) navGeo -> data;
     if (geo -> sp != actTerm -> list) break;
     numStr = g_strdup_printf ("%.6f", geo -> lon);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n%s ", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", geo -> lat);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, numStr);
     g_free (numStr);
   }
 }
 g_string_append (outBuffer, "\n\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteTABTable (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navGeo;
 GEOREF* geo;
 TERMINAL* term;
 FILE* out;
 gchar* numStr;

 iniLen = (20 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append_printf (outBuffer,
    "Dataset\tDate collected\tCollector\tCatalogue No\tIdentifier\tScientific name\tLatitude\tLongitude\tURL\tPrimary reference\n");
 for (navGeo = GETGEOREF; navGeo != NULL; navGeo = g_list_next (navGeo)) {
   UpdateOnCalculus ();
   geo = (GEOREF*) navGeo -> data;
   if (geo -> collec != NULL)
     g_string_append_printf (outBuffer, "%s\t", geo -> collec);
   else
     g_string_append (outBuffer, "\t");
   if (geo -> sampleDate != NULL)
     g_string_append_printf (outBuffer, "%s\t", geo -> sampleDate);
   else
     g_string_append (outBuffer, "\t");
   if (geo -> collector != NULL)
     g_string_append_printf (outBuffer, "%s\t", geo -> collector);
   else
     g_string_append (outBuffer, "\t");
   if (geo -> catalog != NULL)
     g_string_append_printf (outBuffer, "%s\t", geo -> catalog);
   else
     g_string_append (outBuffer, "\t");
   if (geo -> identifier != NULL)
     g_string_append_printf (outBuffer, "%s\t", geo -> identifier);
   else
     g_string_append (outBuffer, "\t");
   if (geo -> name != NULL)
     g_string_append_printf (outBuffer, "%s\t", geo -> name);
   else {
     term = (TERMINAL*) geo -> sp -> data;
     if (term -> name != NULL)
       g_string_append_printf (outBuffer, "%s\t", term -> name);
     else
       g_string_append (outBuffer, "\t");
   }
   numStr = g_strdup_printf ("%.6f", geo -> lat);
   CheckRealStr (numStr);
   g_string_append_printf (outBuffer, "%s\t", numStr);
   g_free (numStr);
   numStr = g_strdup_printf ("%.6f", geo -> lon);
   CheckRealStr (numStr);
   g_string_append_printf (outBuffer, "%s\t", numStr);
   g_free (numStr);
   if (geo -> url != NULL)
     g_string_append_printf (outBuffer, "%s\t", geo -> url);
   else
     g_string_append (outBuffer, "\t");
   if (geo -> reference != NULL)
     g_string_append_printf (outBuffer, "%s\n", geo -> reference);
   else
     g_string_append (outBuffer, "\n");
 }
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteLstFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navSpp;
 TERMINAL* actSp;
 FILE* out;
 GList* termList;
 GList* navName;
 GString* name;

 iniLen = (50 * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);
 termList = NULL;
 /* Sort the list alphabetically */
 for (navSpp = GETSPP; navSpp != NULL; navSpp = g_list_next (navSpp)) {
   UpdateOnCalculus ();
   actSp = (TERMINAL*) navSpp -> data;
   termList = NameOnList (actSp -> name, termList);
 }
 for (navName = termList; navName != NULL; navName = g_list_next (navName)) {
   UpdateOnCalculus ();
   name = (GString*) navName -> data;
   g_string_append_printf (outBuffer, "%s\n", name -> str);
 }
 for (navName = termList; navName != NULL; navName = g_list_next (navName))
   g_string_free (navName -> data, TRUE);
 g_list_free (termList);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteCllFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navRec;
 GEOREF* actRec;
 FILE* out;
 GList* collecList;
 GList* navName;
 GString* name;

 iniLen = (50 * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);
 collecList = NULL;
 /* Sort the list alphabetically */
 for (navRec = GETGEOREF; navRec != NULL; navRec = g_list_next (navRec)) {
   UpdateOnCalculus ();
   actRec = (GEOREF*) navRec -> data;
   if (actRec -> collec != NULL)
     collecList = NameOnList (actRec -> collec, collecList);
 }
 for (navName = collecList; navName != NULL; navName = g_list_next (navName)) {
   UpdateOnCalculus ();
   name = (GString*) navName -> data;
   g_string_append_printf (outBuffer, "%s\n", name -> str);
 }
 for (navName = collecList; navName != NULL; navName = g_list_next (navName))
   g_string_free (navName -> data, TRUE);
 g_list_free (collecList);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteOutLog (gchar* fileName, GString* outBuffer) {
 FILE* out;

 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
}

/* This functions ensure that the out uses points and not commas, This is because my system uses spanish system (i.e. commas) !!" */
void CheckRealStr (gchar* num) {
 SCOUNTER c;

 for (c = 0; ; ++ c) {
   if (num [c] == '.') break;
   if (num [c] == ',') {
     num [c] = '.';
     break;
   }
   if (num [c] == 0) break;
 }
}

GString* DateString (gchar* date) {
 GString* toRet;
 SCOUNTER c;

 toRet = g_string_sized_new (16);
 for (c = 0; ; ++ c) {
   if (date [c] == 0) break;
   if (g_ascii_isspace (date [c])) break;
   g_string_append_c (toRet, date [c]);
 }
 g_string_append_c (toRet, 0);
 return toRet;
}

gchar* CheckExtention (gchar* name, gchar* extention) {
 SCOUNTER c;
 SFLAG noExt;
 gchar* toRet;

 noExt = TRUE;
 for (c = 0; ; ++c) {
   if (name [c] == '\0') {
     noExt = TRUE;
     break;
   }
   if (name [c] == '.') {
     noExt = FALSE;
     continue;
   }
   if ((noExt == FALSE) && (!(g_ascii_isspace (name [c])))) break;
 }
 toRet = name;
 if (noExt == TRUE) {
   toRet = g_strdup_printf ("%s.%s", name, extention);
   g_free (name);
 }
 return toRet;
}

void WriteNodeWithData (GNode* actNode, GString* outBuffer) {
 GNode* navNode;
 GList* navGeo;
 GList* navName;
 PHYLONODE* node;
 PHYLONODE* desc;
 GEOREF* geo;
 SFLAG isOpen;
 gchar* numStr;
 SCOUNTER c;

 UpdateOnCalculus ();
 node = (PHYLONODE*) actNode -> data;
 if (node -> withData == 0) return;
 /* If the node is a term, write it and returns */
 if (node -> term != NULL) {
   g_string_append_printf (outBuffer, "\n\t<Node id=\"%ld\">", node -> id);
   if (node -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", node -> name);
   if ((node -> minAge > 0) && (node -> minAge != NO_AGE))
     g_string_append_printf (outBuffer, "\n\t\t<age>%ld</age>", node -> minAge);
   for (c = 0; ; ++ c) {
     navName = g_list_nth (node -> term -> synonyms, c);
     if (navName == NULL) break;
     if (navName -> data == node -> term -> name) continue;
     g_string_append_printf (outBuffer, "\n\t\t<synonym>%s</synonym>", (gchar*) navName -> data);
   }
   for (navGeo = node -> term -> firstGeo; navGeo != NULL; navGeo = g_list_next (navGeo)) {
     UpdateOnCalculus ();
     geo = (GEOREF*) navGeo -> data;
     if (geo -> sp != node -> term -> list) break;
     g_string_append (outBuffer, "\n\t\t<SpecimenInfo>");
     if (geo -> name != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<name>%s</name>", geo -> name);
     if (geo -> collec != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<collection>%s</collection>", geo -> collec);
     if (geo -> catalog != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<catalogCode>%s</catalogCode>", geo -> catalog);
     if (geo -> url != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<url>%s</url>", geo -> url);
     if (geo -> reference != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<reference>%s</reference>", geo -> reference);
     if (geo -> identifier != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<identifiedBy>%s</identifiedBy>", geo -> identifier);
     if (geo -> sampleDate != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<collectionDate>%s</collectionDate>", geo -> sampleDate);
     if (geo -> collector != NULL)
       g_string_append_printf (outBuffer, "\n\t\t\t<collector>%s</collector>", geo -> collector);
     g_string_append (outBuffer, "\n\t\t\t<Point>");
     g_string_append (outBuffer, "\n\t\t\t\t<coordinates>");
     numStr = g_strdup_printf ("%.6f", geo -> lon);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", geo -> lat);
     CheckRealStr (numStr);
     g_string_append (outBuffer, numStr);
     g_free (numStr);
     g_string_append (outBuffer, "</coordinates>");
     g_string_append (outBuffer, "\n\t\t\t</Point>\n\t\t</SpecimenInfo>");
   }
   g_string_append (outBuffer, "\n\t</Node>");
   return;
 }
 isOpen = FALSE;
 /* Checks if the number of nodes with data is diferent in any descendant */
 for (navNode = g_node_first_child (actNode); navNode != NULL; navNode = g_node_next_sibling (navNode)) {
   desc = (PHYLONODE*) navNode -> data;
   if ((desc -> withData > 0) && (desc -> withData != node -> withData)) {
     isOpen = TRUE;
     break;
   }
 }
 if (isOpen == TRUE) {
   g_string_append_printf (outBuffer, "\n\t<Node id=\"%ld\">", node -> id);
   if (node -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", node -> name);
   if ((node -> minAge > 0) && (node -> minAge != NO_AGE))
     g_string_append_printf (outBuffer, "\n\t\t<age>%ld</age>", node -> minAge);
 }
 /* Write descendants */
 for (navNode = g_node_first_child (actNode); navNode != NULL; navNode = g_node_next_sibling (navNode))
   WriteNodeWithData (navNode, outBuffer);
 if (isOpen == TRUE)
   g_string_append (outBuffer, "\n\t</Node>");
 return;
}

void WriteXMLWithData (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navTree;
 PHYLOTREE* tree;
 FILE* out;

 iniLen = (85 * GETNUMSPP) + (65 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append (outBuffer, "\n\n<Vip>");
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   tree = (PHYLOTREE*) navTree -> data;
   g_string_append (outBuffer, "\n<Tree>");
   if (tree -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t<name>%s</name>", tree -> name);
   WriteNodeWithData (tree -> root, outBuffer);
   g_string_append (outBuffer, "\n</Tree>");
 }
 g_string_append (outBuffer, "\n\n</Vip>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteSVGFile (gchar* fileName, PHYLOTREE* tree, SFLAG withRec) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;
 GNode* navNode;
 PHYLONODE* node;
 PHYLONODE* ancNode;
 SINTEGER endX, startX, startY;
 gchar* text;

 node = (PHYLONODE*) tree -> root -> data;
 iniLen = (80 * node -> numTerms);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append_printf (outBuffer, "\n<svg width=\"%ld\" height=\"%ld\" xmlns=\"http://www.w3.org/2000/svg\">",
                                    tree -> x + 100, tree -> y);
 g_string_append_printf (outBuffer, "\n\t<desc>Tree %s</desc>", tree -> name);
 g_string_append (outBuffer,
                  "\n\t<g stroke-width=\"1\" stroke=\"black\" stroke-linecap=\"round\" font-family=\"Verdana\" font-size=\"10\">");
 for (navNode = tree -> root; navNode != NULL; ) {
   UpdateOnCalculus ();
   node = (PHYLONODE*) navNode -> data;
   if (node -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t\t<!-- Node: %s -->", node -> name);
   else
     g_string_append_printf (outBuffer, "\n\t\t<!-- Node -->");
   /* draws the horizontal line */
   if (navNode -> parent != NULL) {
     ancNode = (PHYLONODE*) navNode -> parent -> data;
     endX = ancNode -> actX;
   }
   else {
     ancNode = NULL;
     endX = node -> actX - 2;
   }
   g_string_append_printf (outBuffer,"\n\t\t<line x1=\"%ld\" y1=\"%ld\" x2=\"%ld\" y2=\"%ld\" />",
                              node -> actX, node -> actY, endX, node -> actY);
   if ((g_node_first_child (navNode) == NULL) && (node -> name != NULL)) {
     /* write the term name */
     g_string_append_printf (outBuffer,"\n\t\t<text x=\"%ld\" y=\"%ld\" stroke-width=\"0\">%s</text>",
                                node -> actX + 5, node -> actY + 5, node -> name);
     if ((withRec & SVG_WITH_REC) && (node -> rec -> nodeFlag & REMOV_NODE))
          g_string_append_printf (outBuffer, "\n\t\t<circle cx=\"%ld\" cy=\"%ld\" r=\"2\" fill=\"white\" stroke=\"black\" />",
               node -> actX, node -> actY);
   }
   else if (g_node_first_child (navNode) != NULL) {
     /* draws the vertical line */
     g_string_append_printf (outBuffer,"\n\t\t<line x1=\"%ld\" y1=\"%ld\" x2=\"%ld\" y2=\"%ld\" />",
                                        node -> actX, node -> topY, node -> actX, node -> downY);
     if (withRec & SVG_WITH_REC) {
       if (node -> rec -> nodeFlag & VIC_NODE) {
         startX = node -> actX - 2;
         startY = node -> actY - 2;
         if (node -> rec -> nodeFlag & REMOV_NODE)
           g_string_append_printf (outBuffer,
              "\n\t\t<rect x=\"%ld\" y=\"%ld\" width=\"5\" height=\"5\" fill=\"white\" stroke=\"black\" />", startX, startY);
         else if (node -> rec -> removSet != NULL) {
           g_string_append_printf (outBuffer,
              "\n\t\t<rect x=\"%ld\" y=\"%ld\" width=\"5\" height=\"5\" fill=\"white\" stroke=\"black\" />", startX, startY);
           g_string_append_printf (outBuffer,"\n\t\t<line x1=\"%ld\" y1=\"%ld\" x2=\"%ld\" y2=\"%ld\" />",
                                        startX, startY, startX + 5, startY + 5);
         }
         else if (node -> rec -> nodeFlag & TIME_LAG)
           g_string_append_printf (outBuffer,
              "\n\t\t<rect x=\"%ld\" y=\"%ld\" width=\"5\" height=\"5\" fill=\"darkgrey\" stroke=\"black\" />", startX, startY);
         else
           g_string_append_printf (outBuffer,
              "\n\t\t<rect x=\"%ld\" y=\"%ld\" width=\"5\" height=\"5\" fill=\"black\" stroke=\"black\" />", startX, startY);
         if (withRec & SVG_WITH_SUPP) {
           if (node -> bremer > node -> tree -> worst)
             text = g_strdup_printf ("?> %.2f", node -> tree -> worst - node -> tree -> best);
           else
             text = g_strdup_printf ("%.2f", node -> bremer - node -> tree -> best);
           CheckRealStr (text);
           g_string_append_printf (outBuffer,"\n\t\t<text x=\"%ld\" y=\"%ld\" stroke-width=\"0\">%s</text>",
                                   node -> actX + 5, node -> actY + 5, text);
           g_free (text);
         }
       }
       else if (node -> rec -> nodeFlag & REMOV_NODE)
          g_string_append_printf (outBuffer, "\n\t\t<circle cx=\"%ld\" cy=\"%ld\" r=\"2\" fill=\"white\" stroke=\"black\" />",
               node -> actX, node -> actY);
     }
     navNode = g_node_first_child (navNode);
     continue;
   }
   while (navNode != NULL) {
     if (g_node_next_sibling (navNode) != NULL) {
       navNode = g_node_next_sibling (navNode);
       break;
     }
     navNode = navNode -> parent;
   }
 }
 g_string_append (outBuffer,"\n\t</g>\n</svg>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WritePhyTree (gchar* fileName, PHYLOTREE* tree) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;

 iniLen = (85 * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append (outBuffer, "\n\n<phyloxml>");
 WritePhyloXMLTree (tree, outBuffer);
 g_string_append (outBuffer, "\n\n</phyloxml>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WritePhyFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navTree;
 PHYLOTREE* tree;
 FILE* out;

 iniLen = (85 * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append (outBuffer, "\n\n<phyloxml>");
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   tree = (PHYLOTREE*) navTree -> data;
   WritePhyloXMLTree (tree, outBuffer);
 }
 g_string_append (outBuffer, "\n\n</phyloxml>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WritePhyloXMLTree (PHYLOTREE* tree, GString* outBuffer) {
 GNode* navNode;
 PHYLONODE* node;

 g_string_append (outBuffer, "\n<phylogeny rooted=\"true\">");
 if (tree -> name != NULL)
   g_string_append_printf (outBuffer, "\n\t<name>%s</name>", tree -> name);
 for (navNode = tree -> root; navNode != NULL; ) {
   UpdateOnCalculus ();
   node = (PHYLONODE*) navNode -> data;
   g_string_append (outBuffer, "\n\t<clade>");
   if (node -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", node -> name);
   if ((node -> minAge > 0) && (node -> minAge != NO_AGE))
     g_string_append_printf (outBuffer, "\n\t\t<date>\n\t\t\t<minimum>%ld</minimum>\n\t\t</date>", node -> minAge);
   if (g_node_first_child (navNode) != NULL) {
     navNode = g_node_first_child (navNode);
     continue;
   }
   while (navNode != NULL) {
     g_string_append (outBuffer, "\n\t</clade>");
     if (g_node_next_sibling (navNode) != NULL) {
       navNode = g_node_next_sibling (navNode);
       break;
     }
     navNode = navNode -> parent;
   }
 }
 g_string_append (outBuffer, "\n</phylogeny>");
}

void WriteCladoTree (gchar* fileName, PHYLOTREE* tree) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;

 iniLen = (85 * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append (outBuffer, "\n\n<Vip>");
 WriteCladoXMLTree (tree, outBuffer);
 g_string_append (outBuffer, "\n\n</Vip>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteCladoFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 GList* navTree;
 PHYLOTREE* tree;
 FILE* out;

 iniLen = (85 * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 g_string_append (outBuffer, "\n\n<Vip>");
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   tree = (PHYLOTREE*) navTree -> data;
   WriteCladoXMLTree (tree, outBuffer);
 }
 g_string_append (outBuffer, "\n\n</Vip>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteCladoXMLTree (PHYLOTREE* tree, GString* outBuffer) {
 GNode* navNode;
 PHYLONODE* node;

 g_string_append (outBuffer, "\n<tree>");
 if (tree -> name != NULL)
   g_string_append_printf (outBuffer, "\n\t<name>%s</name>", tree -> name);
 for (navNode = tree -> root; navNode != NULL; ) {
   UpdateOnCalculus ();
   node = (PHYLONODE*) navNode -> data;
   g_string_append_printf (outBuffer, "\n\t<node id=\"%ld\">", node -> id);
   if (node -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", node -> name);
   if ((node -> minAge > 0) && (node -> minAge != NO_AGE))
     g_string_append_printf (outBuffer, "\n\t\t<age>%ld</age>", node -> minAge);
   if (g_node_first_child (navNode) != NULL) {
     navNode = g_node_first_child (navNode);
     continue;
   }
   while (navNode != NULL) {
     g_string_append (outBuffer, "\n\t</node>");
     if (g_node_next_sibling (navNode) != NULL) {
       navNode = g_node_next_sibling (navNode);
       break;
     }
     navNode = navNode -> parent;
   }
 }
 g_string_append (outBuffer, "\n</tree>");
}

void WriteKMLRecons (gchar* fileName, GNode* refNode, SFLAG modeRecords, SFLAG modeRemoved) {
 gsize iniLen;
 GString* outBuffer;
 PHYLONODE* node;
 FILE* out;

 node = (PHYLONODE*) refNode -> data;
 iniLen = (85 * node -> numTerms) + (65 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\"?><kml xmlns=\"http://earth.google.com/kml/2.1\">");
 g_string_append (outBuffer, "\n\n<Document>");
 g_string_append_printf (outBuffer, "\n\t<name>%s</name>", fileName);
 g_string_append (outBuffer, "\n\t<description><![CDATA[<p>KML file generated by VIP (Arias, 2009)</p>");
 g_string_append (outBuffer, "\n\t\t<p>Useful links:<br>");
 g_string_append (outBuffer, "<a href=\"http://www.zmuc.dk/public/phylogeny/VIP\">");
 g_string_append (outBuffer, "www.zmuc.dk/public/phylogeny/VIP</a>: VIP download<br />");
 g_string_append (outBuffer, "\n\t\t<a href=\"mailto:sal.arias@gmail.com\">sal.arias@gmail.com</a>: ");
 g_string_append (outBuffer, "Salva e-mail</p>\n\t\t<p><b>Acknowledgment</b><br />Pablo, Claudia, ");
 g_string_append (outBuffer, "and Lolo, for suggestions and interest!</p>]]></description>\n");
 g_string_append (outBuffer, "\n");
 if (modeRecords == TRUE) {
   g_string_append (outBuffer,
                          "\n<Style id=\"overlapStyle\">\n\t<IconStyle>\n\t\t<color>ff00ff00</color>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer,
                           "\n<Style id=\"setAStyle\">\n\t<IconStyle>\n\t\t<color>ffff0000</color>\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer,
                           "\n<Style id=\"setBStyle\">\n\t<IconStyle>\n\t\t<color>ff0000ff</color>\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer,
                           "\n<Style id=\"removStyle\">\n\t<IconStyle>\n\t\t<color>ff000000</color>\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
 }
 else {
   g_string_append (outBuffer, "<Style id=\"overlapStyle\">\n\t<PolyStyle>\n\t\t<color>9900ff00</color>\n\t</PolyStyle>\n</Style>");
   g_string_append (outBuffer, "<Style id=\"setAStyle\">\n\t<PolyStyle>\n\t\t<color>99ff0000</color>\n\t</PolyStyle>\n</Style>");
   g_string_append (outBuffer, "<Style id=\"setBStyle\">\n\t<PolyStyle>\n\t\t<color>990000ff</color>\n\t</PolyStyle>\n</Style>");
 }
 g_string_append (outBuffer, "\n");
 if ((node -> rec != NULL) && (node -> rec -> nodeFlag & VIC_NODE)) {
   g_string_append_printf (outBuffer, "\n<Folder>");
   if (node -> name != NULL)
     g_string_append_printf (outBuffer, "\n\t<name>%s</name>", node -> name);
   g_string_append (outBuffer, "\n\t<description><![CDATA[<p>Vicariant distribution</p>]]></description>\n");
   WriteKMLSingle (node -> rec -> setA -> node, node -> rec -> setB -> rec -> cells, modeRecords, modeRemoved, "setAStyle",
                   outBuffer);
   WriteKMLSingle (node -> rec -> setB -> node, node -> rec -> setA -> rec -> cells, modeRecords, modeRemoved, "setBStyle",
                   outBuffer);
   g_string_append_printf (outBuffer, "\n</Folder>");
 }
 else
   WriteKMLSingle (refNode, NULL, modeRecords, modeRemoved, "overlapStyle", outBuffer);
 g_string_append (outBuffer, "\n\n</Document>\n</kml>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteKMLTree (gchar* fileName, PHYLOTREE* tree, SFLAG modeRecords, SFLAG modeRemoved) {
 gsize iniLen;
 GString* outBuffer;
 PHYLONODE* node;
 GNode* refNode;
 FILE* out;
 SCOUNTER i, c;

 node = (PHYLONODE*) tree -> root -> data;
 iniLen = (85 * node -> numTerms) + (65 * GETNUMGEOREFS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\"?><kml xmlns=\"http://earth.google.com/kml/2.1\">");
 g_string_append (outBuffer, "\n\n<Document>");
 g_string_append_printf (outBuffer, "\n\t<name>%s</name>", fileName);
 g_string_append (outBuffer, "\n\t<description><![CDATA[<p>KML file generated by VIP (Arias, 2009)</p>");
 g_string_append (outBuffer, "\n\t\t<p>Useful links:<br>");
 g_string_append (outBuffer, "<a href=\"http://www.zmuc.dk/public/phylogeny/VIP\">");
 g_string_append (outBuffer, "www.zmuc.dk/public/phylogeny/VIP</a>: VIP download<br />");
 g_string_append (outBuffer, "\n\t\t<a href=\"mailto:sal.arias@gmail.com\">sal.arias@gmail.com</a>: ");
 g_string_append (outBuffer, "Salva e-mail</p>\n\t\t<p><b>Acknowledgment</b><br />Pablo, Claudia, ");
 g_string_append (outBuffer, "and Lolo, for suggestions and interest!</p>]]></description>\n");
 g_string_append (outBuffer, "\n");
 if (modeRecords == TRUE) {
   g_string_append (outBuffer,
                          "\n<Style id=\"overlapStyle\">\n\t<IconStyle>\n\t\t<color>ff00ff00</color>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer,
                           "\n<Style id=\"setAStyle\">\n\t<IconStyle>\n\t\t<color>ffff0000</color>\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer,
                           "\n<Style id=\"setBStyle\">\n\t<IconStyle>\n\t\t<color>ff0000ff</color>\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer,
                           "\n<Style id=\"removStyle\">\n\t<IconStyle>\n\t\t<color>ff000000</color>\n\t</IconStyle>\n</Style>");
   g_string_append (outBuffer, "\n\t\t<Icon>\n\t\t\t<href>http://maps.google.com/mapfiles/kml/paddle/wht-blank.png</href>\n\t\t</Icon>");
   g_string_append (outBuffer, "\n\t</IconStyle>\n</Style>");
 }
 else {
   g_string_append (outBuffer, "<Style id=\"overlapStyle\">\n\t<PolyStyle>\n\t\t<color>9900ff00</color>\n\t</PolyStyle>\n</Style>");
   g_string_append (outBuffer, "<Style id=\"setAStyle\">\n\t<PolyStyle>\n\t\t<color>99ff0000</color>\n\t</PolyStyle>\n</Style>");
   g_string_append (outBuffer, "<Style id=\"setBStyle\">\n\t<PolyStyle>\n\t\t<color>990000ff</color>\n\t</PolyStyle>\n</Style>");
 }
 g_string_append (outBuffer, "\n");
 for (i = 0, c = 0; i < tree -> nodeArray -> len; ++ i) {
   UpdateOnCalculus ();
   refNode = (GNode*) g_ptr_array_index (tree -> nodeArray, i);
   node = (PHYLONODE*) refNode -> data;
   if (node -> rec -> nodeFlag & VIC_NODE) {
     ++ c;
     g_string_append_printf (outBuffer, "\n<Folder>");
     if (node -> name != NULL)
       g_string_append_printf (outBuffer, "\n\t<name>%s</name>", node -> name);
     g_string_append_printf (outBuffer, "\n\t<description><![CDATA[<p>Vicariant distribution %ld</p>]]></description>\n", c);
     WriteKMLSingle (node -> rec -> setA -> node, node -> rec -> setB -> rec -> cells, modeRecords, modeRemoved, "setAStyle",
                   outBuffer);
     WriteKMLSingle (node -> rec -> setB -> node, node -> rec -> setA -> rec -> cells, modeRecords, modeRemoved, "setBStyle",
                   outBuffer);
     g_string_append_printf (outBuffer, "\n</Folder>");
   }
 }
 g_string_append (outBuffer, "\n\n</Document>\n</kml>\n");
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteKMLSingle (GNode* refNode, BITFIELD* outCells, SFLAG modeRecords, SFLAG modeRemoved, gchar* style,
                     GString* outBuffer) {
 GNode* actNode;
 GList* navGeo;
 PHYLONODE* node;
 PHYLONODE* anc;
 TERMINAL* term;
 GEOREF* geo;
 BITFIELD* inCells;
 SFLAG in, out;
 SREAL x, x1, y, y1;
 SCOUNTER c, sX, sY;
 gchar* numStr;
 GString* date;

 node = (PHYLONODE*) refNode -> data;
 g_string_append_printf (outBuffer, "\n<Folder>");
 if (node -> name != NULL)
   g_string_append_printf (outBuffer, "\n\t<name>%s</name>", node -> name);
 if (modeRecords == TRUE) {
   if (node -> rec != NULL)
     inCells = node -> rec -> cells;
   else
     inCells = NULL;
   for (actNode = refNode; actNode != NULL;) {
     if (IsDesc (actNode, refNode) != TRUE) break;
     UpdateOnCalculus ();
     node = (PHYLONODE*) actNode -> data;
     if (actNode -> parent != NULL)
       anc = (PHYLONODE*) actNode -> parent -> data;
     if ((inCells != NULL) && (actNode != refNode) && ((node -> rec -> numCells == 0) ||
                 (node -> rec -> nodeFlag & REMOV_NODE) || (node == anc -> rec -> removSet))) {
       /* A removed distribution, ignores all of its descendants */
       while (actNode != NULL) {
         if (g_node_next_sibling (actNode) != NULL) {
           actNode = g_node_next_sibling (actNode);
           break;
         }
         actNode = actNode -> parent;
       }
       continue;
     }
     if (g_node_first_child (actNode) != NULL) {
     /* Not a term, goes to the first descendant */
       actNode = g_node_first_child (actNode);
       continue;
     }
     term = node -> term;
     for (navGeo = term -> firstGeo; navGeo != NULL; navGeo = g_list_next (navGeo)) {
       UpdateOnCalculus ();
       geo = (GEOREF*) navGeo -> data;
       if (term != (TERMINAL*) geo -> sp -> data) break;
       if (inCells != NULL) {
         in = IsBitOn (inCells, geo -> actCell);
         if (outCells != NULL)
           out = IsBitOn (outCells, geo -> actCell);
         else
           out = FALSE;
       }
       else {
         in = TRUE;
         out = FALSE;
       }
       if (in != TRUE) {
         if (modeRemoved == TRUE) {
           g_string_append (outBuffer, "\n\t<Placemark>");
           if (geo -> name != NULL)
             g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", geo -> name);
           g_string_append (outBuffer, "\n\t\t<styleUrl>#removStyle</styleUrl>");
         }
         else continue;
       }
       else if ((in == TRUE) && (out != TRUE)) {
         g_string_append (outBuffer, "\n\t<Placemark>");
         if (geo -> name != NULL)
           g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", geo -> name);
         g_string_append_printf (outBuffer, "\n\t\t<styleUrl>#%s</styleUrl>", style);
       }
       else {
         g_string_append (outBuffer, "\n\t<Placemark>");
         if (geo -> name != NULL)
           g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", geo -> name);
         g_string_append (outBuffer, "\n\t\t<styleUrl>#overlapStyle</styleUrl>");
       }
       g_string_append (outBuffer, "\n\t\t<description><![CDATA[<p>");
       if (geo -> name != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tTerminal: %s<br />", geo -> name);
       if (geo -> collec != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCollection: %s<br />", geo -> collec);
       if (geo -> catalog != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCatalogue code: %s <br />", geo -> catalog);
       if (geo -> url != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tUrl: <a hfer=\"%s\">%s</a><br />", geo -> url, geo -> url);
       if (geo -> reference != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tReference: %s<br />", geo -> reference);
       if (geo -> identifier != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tIdentified by: %s<br />", geo -> identifier);
       if (geo -> sampleDate != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCollection date: %s<br />", geo -> sampleDate);
       if (geo -> collector != NULL)
         g_string_append_printf (outBuffer, "\n\t\t\tCollector: %s<br />", geo -> collector);
       g_string_append (outBuffer, "\n\t\t</p>]]></description>");
       if (geo -> sampleDate != NULL) {
         date = DateString (geo -> sampleDate);
         g_string_append (outBuffer, "\n\t\t<TimeStap>");
         g_string_append_printf (outBuffer, "\n\t\t\t<when>%s</when>", date -> str);
         g_string_append (outBuffer, "\n\t\t</TimeStap>");
         g_string_free (date, TRUE);
       }
       g_string_append (outBuffer, "\n\t\t<Point>");
       g_string_append (outBuffer, "\n\t\t\t<extrude>0</extrude>");
       g_string_append (outBuffer, "\n\t\t\t<altitudeMode>absolute</altitudeMode>");
       g_string_append (outBuffer, "\n\t\t\t<coordinates>");
       numStr = g_strdup_printf ("%.6f", geo -> lon);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", geo -> lat);
       CheckRealStr (numStr);
       g_string_append (outBuffer, numStr);
       g_free (numStr);
       g_string_append (outBuffer, "</coordinates>");
       g_string_append (outBuffer, "\n\t\t</Point>\n\t</Placemark>");
     }
     while (actNode != NULL) {
       if (g_node_next_sibling (actNode) != NULL) {
         actNode = g_node_next_sibling (actNode);
         break;
       }
       actNode = actNode -> parent;
     }
   }
 }
 else {
   for (c = 0; c < GETNUMCELLS; ++ c) {
     UpdateOnCalculus ();
     if (IsBitOn (node -> rec -> cells, c)) {
       GetColRowFromCell (c, &sY, &sX);
       x = ((GETGRIDSIZE * sX) + GETGRIDSTARTX);
       x = FROMAZMTOLON (x);
       x1 = ((GETGRIDSIZE * (sX + 1)) + GETGRIDSTARTX);
       x1 = FROMAZMTOLON (x1);
       y = ((GETGRIDSIZE * sY) + GETGRIDSTARTY);
       y = FROMINCTOLAT (y);
       y1 = ((GETGRIDSIZE * (sY + 1)) + GETGRIDSTARTY);
       y1 = FROMINCTOLAT (y1);
       g_string_append (outBuffer, "\n\t<Placemark>");
       if (node -> name != NULL)
          g_string_append_printf (outBuffer, "\n\t\t<name>%s</name>", node -> name);
       if (outCells != NULL)
         out = IsBitOn (outCells, c);
       else
         out = FALSE;
       if (out != TRUE)
         g_string_append_printf (outBuffer, "\n\t\t<styleUrl>#%s</styleUrl>", style);
       else
         g_string_append (outBuffer, "\n\t\t<styleUrl>#overlapStyle</styleUrl>");
       g_string_append (outBuffer, "\n\t\t<Polygon>");
       g_string_append (outBuffer, "\n\t\t\t<outerBoundaryIs>\n\t\t\t\t<LinearRing>\n\t\t\t\t\t<coordinates>");
       numStr = g_strdup_printf ("%.6f", x);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", y);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", x1);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", y);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", x1);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", y1);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", x);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", y1);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", x);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
       g_free (numStr);
       numStr = g_strdup_printf ("%.6f", y);
       CheckRealStr (numStr);
       g_string_append_printf (outBuffer, "%s", numStr);
       g_free (numStr);
       g_string_append (outBuffer, "\n\t\t\t\t\t</coordinates>\n\t\t\t\t</LinearRing>\n\t\t\t</outerBoundaryIs>");
       g_string_append (outBuffer, "\n\t\t</Polygon>\n\t</Placemark>");
     }
   }
 }
 g_string_append_printf (outBuffer, "\n</Folder>");
}

void WriteNewickFile (gchar* fileName, PHYLOTREE* tree, SFLAG mode) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;
 GNode* navNode;
 PHYLONODE* node;
 PHYLONODE* anc;
 SCOUNTER i, id, terms;
 INTARRAY* termIds;

 if (tree == NULL) return;
 iniLen = (85 * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);
 node = (PHYLONODE*) tree -> root -> data;

 if (mode & USE_NEXUS) {
   g_string_append (outBuffer, "#NEXUS\n");
   if (tree -> name != NULL)
     g_string_append_printf (outBuffer, "\n[ %s ]", tree -> name);
   g_string_append (outBuffer, "\nbegin trees;");
   if (!(mode & USE_NAMES))
     g_string_append (outBuffer, "\ntranslate");
 }
 if (mode == USE_TNT) {
   g_string_append (outBuffer, "xread");
   if (tree -> name != NULL)
     g_string_append_printf (outBuffer, "\n\' %s \'", tree -> name);
   g_string_append_printf (outBuffer, "1 %ld", node -> numTerms);
 }
 terms = node -> numTerms;
 termIds = CreateIntArray (terms);
 for (i = 0; i < tree -> nodeArray -> len; ++ i) {
   navNode = (GNode*) g_ptr_array_index (tree -> nodeArray, i);
   if (g_node_first_child (navNode) != NULL) continue;
   node = (PHYLONODE*) navNode -> data;
   AddToArray (termIds, node -> id);
 }
 if (!(mode & USE_NAMES)) {
   for (i = 0; i < terms; ++ i) {
     UpdateOnCalculus ();
     id = GetFromArray (termIds, i);
     node = GetNodeFromID (tree, id);
     if (mode == USE_NEXUS) {
       if (node -> name != NULL)
         g_string_append_printf (outBuffer, "\n\t%ld\t%s", i + 1, node -> name);
       else
         g_string_append_printf (outBuffer, "\n\t%ld\tnode_%ld", i + 1, id);
       if ((i + 1) < terms)
         g_string_append (outBuffer, ",");
     }
     if (mode == USE_TNT) {
       if (node -> name != NULL)
         g_string_append_printf (outBuffer, "\n%s          ?", node -> name);
       else
         g_string_append_printf (outBuffer, "\nnode_%ld          ?", id);
     }
   }
   g_string_append (outBuffer, ";");
 }
 if (mode & USE_NEXUS)
   g_string_append_printf (outBuffer, "\n\n\ttree %s = ", (tree -> name != NULL) ? tree -> name : "unnamedtree");
 if (mode & USE_TNT)
   g_string_append (outBuffer, "\n\ntread\n");
 for (navNode = tree -> root; navNode != NULL; ) {
   UpdateOnCalculus ();
   if (g_node_first_child (navNode) != NULL) {
     g_string_append (outBuffer, "(");
     navNode = g_node_first_child (navNode);
     continue;
   }
   node = (PHYLONODE*) navNode -> data;
   i = SearchIndexValue (termIds, node -> id);
   if (mode == USE_NEXUS)
     g_string_append_printf (outBuffer, "%ld", i + 1);
   if (mode == USE_TNT)
     g_string_append_printf (outBuffer, " %ld", i);
   if (mode & USE_NAMES) {
     if (mode & USE_TNT)
       g_string_append (outBuffer, " ");
     if (node -> name != NULL)
       g_string_append_printf (outBuffer, "%s", node -> name);
     else
       g_string_append_printf (outBuffer, "node_%ld", id);
   }
   while (navNode != NULL) {
     if  ((mode & USE_NEXUS) && (node -> minAge > 0) && (navNode -> parent != NULL) && (g_node_first_child (navNode) == NULL)) {
       anc = (PHYLONODE*) navNode -> parent -> data;
       g_string_append_printf (outBuffer, ":%ld", anc -> minAge - node -> minAge);
     }
     if (g_node_first_child (navNode) != NULL)
       g_string_append (outBuffer, ")");
     if  ((mode & USE_NEXUS) && (node -> minAge > 0) && (navNode -> parent != NULL) && (g_node_first_child (navNode) != NULL)) {
       anc = (PHYLONODE*) navNode -> parent -> data;
       g_string_append_printf (outBuffer, ":%ld", anc -> minAge - node -> minAge);
     }
     if (g_node_next_sibling (navNode) != NULL) {
       if (mode & USE_NEXUS)
         g_string_append (outBuffer, ",");
       navNode = g_node_next_sibling (navNode);
       break;
     }
     navNode = navNode -> parent;
   }
 }
 g_string_append (outBuffer, ";\n");
 if (mode & USE_NEXUS)
   g_string_append_printf (outBuffer, "end;\n");
 if (mode & USE_TNT)
   g_string_append (outBuffer, "p/;\n");
 DestroyIntArray (termIds);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

SCOUNTER CalculateRichness (INTARRAY* sppPerCell, INTARRAY* obsPerCell) {
 SCOUNTER cell, num, max;
 GList* spNav;
 TERMINAL* actSp;
 PHYLONODE* actNode;

 for (cell = 0; cell < GETNUMCELLS; ++ cell) {
   if (sppPerCell != NULL)
     AddToArray (sppPerCell, 0);
   AddToArray (obsPerCell, 0);
 }
 max = 0;
 for (spNav = GETSPP; spNav != NULL; spNav = g_list_next (spNav)) {
   UpdateOnCalculus ();
   actSp = (TERMINAL*) spNav -> data;
   actNode = (PHYLONODE*) actSp -> node -> data;
   for (cell = 0; cell < GETNUMCELLS; ++ cell) {
     UpdateOnCalculus ();
     if (!IsBitOn (actNode -> rec -> cells, cell)) continue;
     if (IsBitOn (actSp -> obs, cell))
       InsertValToArray (obsPerCell, 1, cell);
     if (sppPerCell != NULL) {
       num = GetFromArray (sppPerCell, cell) + 1;
       InsertValToArray (sppPerCell, num, cell);
       if (num > max)
         max = num;
     }
     else {
       if (IsBitOn (actNode -> rec -> cells, cell))
         InsertValToArray (obsPerCell, 1, cell);
     }
   }
 }
 return max;
}

void WriteNDMMatrix (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;
 SCOUNTER c, r, cell;
 INTARRAY* obsPerCell;
 GList* spNav;
 GList* navTree;
 PHYLOTREE* actTree;
 TERMINAL* actSp;
 PHYLONODE* actNode;
 gchar* text;

 obsPerCell = CreateIntArray (GETNUMCELLS);
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   actTree = (PHYLOTREE*) navTree -> data;
   SetRec (actTree -> recOR);
 }
 CalculateRichness (NULL, obsPerCell);
 iniLen = (GETNUMCELLS * GETNUMSPP);
 outBuffer = g_string_sized_new (iniLen);

 text = g_strdup_printf ("%.4f", FROMAZMTOLON (GETGRIDSTARTX));
 CheckRealStr (text);
 g_string_append_printf (outBuffer, "gridx %s ", text);
 g_free (text);
 text = g_strdup_printf ("%.4f", GETGRIDSIZE);
 CheckRealStr (text);
 g_string_append_printf (outBuffer, "%s\n", text);
 g_free (text);
 text = g_strdup_printf ("%.4f", FROMINCTOLAT (GETGRIDSTARTY));
 CheckRealStr (text);
 g_string_append_printf (outBuffer, "gridy %s ", text);
 g_free (text);
 text = g_strdup_printf ("%.4f", GETGRIDSIZE);
 CheckRealStr (text);
 g_string_append_printf (outBuffer, "%s\n", text);
 g_free (text);
 g_string_append_printf (outBuffer, "rows %ld\ncols %ld\nspp%ld\ndata", GETNUMROWS, GETNUMCOLS, GETNUMSPP);
 for (r = 0; r < GETNUMROWS; ++ r) {
   for (c = 0; c < GETNUMCOLS; ++ c) {
     UpdateOnCalculus ();
     cell = GetCell (r, c);
     if ((cell == -1) || (GetFromArray (obsPerCell, cell) == 0)) continue;
     g_string_append_printf (outBuffer, "\nA%ld-%ld\t", r, c);
     for (spNav = GETSPP; spNav != NULL; spNav = g_list_next (spNav)) {
       actSp = (TERMINAL*) spNav -> data;
       actNode = (PHYLONODE*) actSp -> node -> data;
       if (IsBitOn (actNode -> rec -> cells, cell))
         g_string_append (outBuffer, "1");
       else
         g_string_append (outBuffer, "0");
     }
   }
 }
 g_string_append (outBuffer, "\n;\n");
 DestroyIntArray (obsPerCell);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteSpRichness (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;
 SCOUNTER c, r;
 SCOUNTER cell, max;
 INTARRAY* sppPerCell;
 INTARRAY* obsPerCell;
 GList* navTree;
 PHYLOTREE* actTree;
 SREAL lat, lon;
 gchar* numStr;

 sppPerCell = CreateIntArray (GETNUMCELLS);
 obsPerCell = CreateIntArray (GETNUMCELLS);
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   actTree = (PHYLOTREE*) navTree -> data;
   SetRec (actTree -> recOR);
 }
 max = CalculateRichness (sppPerCell, obsPerCell);
 iniLen = (3 * GETNUMROWS) * (3 * GETNUMCOLS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "R-C\t");
 for (c = 0; c < GETNUMCOLS; ++ c) {
   lon = GETGRIDSTARTX + (GETGRIDSIZE * c);
   numStr = g_strdup_printf ("%.3f", FROMAZMTOLON (lon));
   CheckRealStr (numStr);
   g_string_append_printf (outBuffer, "%s\t", numStr);
   g_free (numStr);
 }
 for (r = 0; r < GETNUMROWS; ++ r) {
   lat = GETGRIDSTARTY + (GETGRIDSIZE * r);
   numStr = g_strdup_printf ("%.3f", FROMINCTOLAT (lat));
   CheckRealStr (numStr);
   g_string_append_printf (outBuffer, "%s\t", numStr);
   g_free (numStr);
   for (c = 0; c < GETNUMCOLS; ++ c) {
     UpdateOnCalculus ();
     cell = GetCell (r, c);
     if ((cell == -1) || (GetFromArray (obsPerCell, cell) == 0)) {
       g_string_append (outBuffer, "0\t");
       continue;
     }
     numStr = g_strdup_printf ("%.4f", (SREAL) GetFromArray (sppPerCell, cell) / max);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s\t", numStr);
     g_free (numStr);
   }
 }
 DestroyIntArray (sppPerCell);
 DestroyIntArray (obsPerCell);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

SCOUNTER CalculatePD (INTARRAY* pdPerCell, INTARRAY* obsPerCell) {
 SCOUNTER cell, max, toRet, num;
 GList* spNav;
 TERMINAL* actSp;
 GList* navTree;
 PHYLOTREE* actTree;
 PHYLONODE* root;

 for (cell = 0; cell < GETNUMCELLS; ++ cell)
   AddToArray (obsPerCell, 0);
 for (spNav = GETSPP; spNav != NULL; spNav = g_list_next (spNav)) {
   actSp = (TERMINAL*) spNav -> data;
   for (cell = 0; cell < GETNUMCELLS; ++ cell) {
     UpdateOnCalculus ();
     if (!IsBitOn (actSp -> obs, cell)) continue;
     InsertValToArray (obsPerCell, 1, cell);
   }
 }
 max = 0;
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   actTree = (PHYLOTREE*) navTree -> data;
   root = (PHYLONODE*) actTree -> root -> data;
   if (root -> level > max)
     max = root -> level;
   SetRec (actTree -> recOR);
 }
 toRet = 0;
 for (cell = 0; cell < GETNUMCELLS; ++ cell) {
   UpdateOnCalculus ();
   num = CalculatePhyloDiv (cell, max);
   AddToArray (pdPerCell, num);
   InsertValToArray (pdPerCell, num, cell);
   if (num > toRet)
     toRet = num;
 }
 return toRet;
}

void WritePhyloDiv (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;
 SCOUNTER c, r;
 SCOUNTER cell, max;
 INTARRAY* obsPerCell;
 INTARRAY* pdPerCell;
 SREAL lat, lon;
 gchar* numStr;

 pdPerCell = CreateIntArray (GETNUMCELLS);
 obsPerCell = CreateIntArray (GETNUMCELLS);
 max = CalculatePD (pdPerCell, obsPerCell);
 iniLen = (3 * GETNUMROWS) * (3 * GETNUMCOLS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "R-C\t");
 for (c = 0; c < GETNUMCOLS; ++ c) {
   UpdateOnCalculus ();
   lon = GETGRIDSTARTX + (GETGRIDSIZE * c);
   numStr = g_strdup_printf ("%.3f", FROMAZMTOLON (lon));
   CheckRealStr (numStr);
   g_string_append_printf (outBuffer, "%s\t", numStr);
   g_free (numStr);
 }
 for (r = 0; r < GETNUMROWS; ++ r) {
   UpdateOnCalculus ();
   lat = GETGRIDSTARTY + (GETGRIDSIZE * r);
   numStr = g_strdup_printf ("%.3f", FROMINCTOLAT (lat));
   CheckRealStr (numStr);
   g_string_append_printf (outBuffer, "%s\t", numStr);
   g_free (numStr);
   for (c = 0; c < GETNUMCOLS; ++ c) {
     cell = GetCell (r, c);
     if ((cell == -1) || (GetFromArray (obsPerCell, cell) == 0)) {
       g_string_append (outBuffer, "0\t");
       continue;
     }
     numStr = g_strdup_printf ("%.4f", (SREAL) GetFromArray (pdPerCell, cell) / max);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s\t", numStr);
     g_free (numStr);
   }
 }
 DestroyIntArray (pdPerCell);
 DestroyIntArray (obsPerCell);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WriteRichKMLFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;
 gchar hexStr [3];
 INTARRAY* sppPerCell;
 INTARRAY* obsPerCell;
 SCOUNTER i, cell, max, num, r, c;
 SREAL x, x1, y, y1;
 gchar* numStr;
 GList* navTree;
 PHYLOTREE* actTree;

 sppPerCell = CreateIntArray (GETNUMCELLS);
 obsPerCell = CreateIntArray (GETNUMCELLS);
 for (navTree = GETTREES; navTree != NULL; navTree = g_list_next (navTree)) {
   actTree = (PHYLOTREE*) navTree -> data;
   SetRec (actTree -> recOR);
 }
 max = CalculateRichness (sppPerCell, obsPerCell);
 iniLen = (80 * GETNUMROWS * GETNUMCOLS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\"?><kml xmlns=\"http://earth.google.com/kml/2.1\">");
 g_string_append (outBuffer, "\n\n<Document>");
 g_string_append_printf (outBuffer, "\n\t<name>%s</name>", fileName);
 g_string_append (outBuffer, "\n\t<description><![CDATA[<p>KML file generated by VIP (Arias, 2009)</p>");
 g_string_append (outBuffer, "\n\t\t<p>Useful links:<br>");
 g_string_append (outBuffer, "<a href=\"http://www.zmuc.dk/public/phylogeny/VIP\">");
 g_string_append (outBuffer, "www.zmuc.dk/public/phylogeny/VIP</a>: VIP download<br />");
 g_string_append (outBuffer, "\n\t\t<a href=\"mailto:sal.arias@gmail.com\">sal.arias@gmail.com</a>: ");
 g_string_append (outBuffer, "Salva e-mail</p>\n\t\t<p><b>Acknowledgment</b><br />Pablo, Claudia, ");
 g_string_append (outBuffer, "and Lolo, for suggestions and interest!</p>]]></description>\n");
 g_string_append (outBuffer, "\n");
 for (i = 0; i < 100; ++ i) {
   g_string_append_printf (outBuffer, "<Style id=\"val%ld\">\n\t<PolyStyle>", i + 1);
   if (i < 50) {
     WriteInHex (hexStr, 250 - (5 * i));
     g_string_append_printf (outBuffer, "\n\t\t<color>99%s", hexStr);
     if (i >= 25) {
       WriteInHex (hexStr, 10 * (i - 25));
       g_string_append_printf (outBuffer, "%s00</color>\n\t</PolyStyle>\n</Style>", hexStr);
     }
     else
       g_string_append (outBuffer, "0000</color>\n\t</PolyStyle>\n</Style>");
   }
   else {
     if (i < 75) {
       WriteInHex (hexStr, 250 - (10 * (i - 50)));
       g_string_append_printf (outBuffer, "\n\t\t<color>9900%s", hexStr);
     }
     else
       g_string_append (outBuffer, "\n\t\t<color>990000");
     WriteInHex (hexStr, 5 * (i - 50));
     g_string_append_printf (outBuffer, "%s</color>\n\t</PolyStyle>\n</Style>", hexStr);
   }
 }
 g_string_append (outBuffer, "\n\n<Folder>");
 for (r = 0; r < GETNUMROWS; ++ r) {
   for (c = 0; c < GETNUMCOLS; ++ c) {
     UpdateOnCalculus ();
     cell = GetCell (r, c);
     if ((cell == -1) || (GetFromArray (obsPerCell, cell) == 0)) continue;
     x = ((GETGRIDSIZE * c) + GETGRIDSTARTX);
     x = FROMAZMTOLON (x);
     x1 = ((GETGRIDSIZE * (c + 1)) + GETGRIDSTARTX);
     x1 = FROMAZMTOLON (x1);
     y = ((GETGRIDSIZE * r) + GETGRIDSTARTY);
     y = FROMINCTOLAT (y);
     y1 = ((GETGRIDSIZE * (r + 1)) + GETGRIDSTARTY);
     y1 = FROMINCTOLAT (y1);
     g_string_append (outBuffer, "\n\t<Placemark>");
     g_string_append_printf (outBuffer, "\n\t\t<name>cell%ld</name>", cell);
     num = GetFromArray (sppPerCell, cell);
     numStr = g_strdup_printf ("%.3f", (SREAL) num / max);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer,
            "\n\t\t<description><![CDATA[<p>Richness = %ld (scaled = %s)</p>]]></description>", num, numStr);
     g_free (numStr);
     num = (num * 100) / max;
     g_string_append_printf (outBuffer, "\n\t\t<styleUrl>#val%ld</styleUrl>", num);
     g_string_append (outBuffer, "\n\t\t<Polygon>");
     g_string_append (outBuffer, "\n\t\t\t<outerBoundaryIs>\n\t\t\t\t<LinearRing>\n\t\t\t\t\t<coordinates>");
     numStr = g_strdup_printf ("%.6f", x);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     g_string_append (outBuffer, "\n\t\t\t\t\t</coordinates>\n\t\t\t\t</LinearRing>\n\t\t\t</outerBoundaryIs>");
     g_string_append (outBuffer, "\n\t\t</Polygon>\n\t</Placemark>");
   }
 }
 g_string_append_printf (outBuffer, "\n</Folder>");
 g_string_append (outBuffer, "\n\n</Document>\n</kml>\n");
 DestroyIntArray (sppPerCell);
 DestroyIntArray (obsPerCell);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

void WritePDKMLFile (gchar* fileName) {
 gsize iniLen;
 GString* outBuffer;
 FILE* out;
 gchar hexStr [3];
 INTARRAY* pdPerCell;
 INTARRAY* obsPerCell;
 SCOUNTER i, cell, max, num, r, c;
 SREAL x, x1, y, y1;
 gchar* numStr;

 pdPerCell = CreateIntArray (GETNUMCELLS);
 obsPerCell = CreateIntArray (GETNUMCELLS);
 max = CalculatePD (pdPerCell, obsPerCell);
 iniLen = (80 * GETNUMROWS * GETNUMCOLS);
 outBuffer = g_string_sized_new (iniLen);
 g_string_append (outBuffer, "<?xml version=\"1.0\"?><kml xmlns=\"http://earth.google.com/kml/2.1\">");
 g_string_append (outBuffer, "\n\n<Document>");
 g_string_append_printf (outBuffer, "\n\t<name>%s</name>", fileName);
 g_string_append (outBuffer, "\n\t<description><![CDATA[<p>KML file generated by VIP (Arias, 2009)</p>");
 g_string_append (outBuffer, "\n\t\t<p>Useful links:<br>");
 g_string_append (outBuffer, "<a href=\"http://www.zmuc.dk/public/phylogeny/VIP\">");
 g_string_append (outBuffer, "www.zmuc.dk/public/phylogeny/VIP</a>: VIP download<br />");
 g_string_append (outBuffer, "\n\t\t<a href=\"mailto:sal.arias@gmail.com\">sal.arias@gmail.com</a>: ");
 g_string_append (outBuffer, "Salva e-mail</p>\n\t\t<p><b>Acknowledgment</b><br />Pablo, Claudia, ");
 g_string_append (outBuffer, "and Lolo, for suggestions and interest!</p>]]></description>\n");
 g_string_append (outBuffer, "\n");
 for (i = 0; i < 100; ++ i) {
   g_string_append_printf (outBuffer, "<Style id=\"val%ld\">\n\t<PolyStyle>", i + 1);
   if (i < 50) {
     WriteInHex (hexStr, 250 - (5 * i));
     g_string_append_printf (outBuffer, "\n\t\t<color>99%s", hexStr);
     if (i >= 25) {
       WriteInHex (hexStr, 10 * (i - 25));
       g_string_append_printf (outBuffer, "%s00</color>\n\t</PolyStyle>\n</Style>", hexStr);
     }
     else
       g_string_append (outBuffer, "0000</color>\n\t</PolyStyle>\n</Style>");
   }
   else {
     if (i < 75) {
       WriteInHex (hexStr, 250 - (10 * (i - 50)));
       g_string_append_printf (outBuffer, "\n\t\t<color>9900%s", hexStr);
     }
     else
       g_string_append (outBuffer, "\n\t\t<color>990000");
     WriteInHex (hexStr, 5 * (i - 50));
     g_string_append_printf (outBuffer, "%s</color>\n\t</PolyStyle>\n</Style>", hexStr);
   }
 }
 g_string_append (outBuffer, "\n\n<Folder>");
 for (r = 0; r < GETNUMROWS; ++ r) {
   for (c = 0; c < GETNUMCOLS; ++ c) {
     UpdateOnCalculus ();
     cell = GetCell (r, c);
     if ((cell == -1) || (GetFromArray (obsPerCell, cell) == 0)) continue;
     x = ((GETGRIDSIZE * c) + GETGRIDSTARTX);
     x = FROMAZMTOLON (x);
     x1 = ((GETGRIDSIZE * (c + 1)) + GETGRIDSTARTX);
     x1 = FROMAZMTOLON (x1);
     y = ((GETGRIDSIZE * r) + GETGRIDSTARTY);
     y = FROMINCTOLAT (y);
     y1 = ((GETGRIDSIZE * (r + 1)) + GETGRIDSTARTY);
     y1 = FROMINCTOLAT (y1);
     g_string_append (outBuffer, "\n\t<Placemark>");
     g_string_append_printf (outBuffer, "\n\t\t<name>cell%ld</name>", cell);
     num = GetFromArray (pdPerCell, cell);
     numStr = g_strdup_printf ("%.3f", (SREAL) num / max);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer,
            "\n\t\t<description><![CDATA[<p>PD = %ld (scaled = %s)</p>]]></description>", num, numStr);
     g_free (numStr);
     num = (num * 100) / max;
     g_string_append_printf (outBuffer, "\n\t\t<styleUrl>#val%ld</styleUrl>", num);
     g_string_append (outBuffer, "\n\t\t<Polygon>");
     g_string_append (outBuffer, "\n\t\t\t<outerBoundaryIs>\n\t\t\t\t<LinearRing>\n\t\t\t\t\t<coordinates>");
     numStr = g_strdup_printf ("%.6f", x);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y1);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", x);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "\n\t\t\t\t\t\t%s,", numStr);
     g_free (numStr);
     numStr = g_strdup_printf ("%.6f", y);
     CheckRealStr (numStr);
     g_string_append_printf (outBuffer, "%s", numStr);
     g_free (numStr);
     g_string_append (outBuffer, "\n\t\t\t\t\t</coordinates>\n\t\t\t\t</LinearRing>\n\t\t\t</outerBoundaryIs>");
     g_string_append (outBuffer, "\n\t\t</Polygon>\n\t</Placemark>");
   }
 }
 g_string_append_printf (outBuffer, "\n</Folder>");
 g_string_append (outBuffer, "\n\n</Document>\n</kml>\n");
 DestroyIntArray (pdPerCell);
 DestroyIntArray (obsPerCell);
 out = fopen (fileName, "w");
 if (out == NULL) {
   errorMessage = g_strdup_printf ("\nUnable to open %s\n", fileName);
   OnError ();
   g_string_free (outBuffer, TRUE);
   return;
 }
 if (fwrite (outBuffer -> str, sizeof (gchar), outBuffer -> len, out) != outBuffer -> len) {
   errorMessage = g_strdup_printf ("\nUnable to save whole data\nFile%s\n", fileName);
   OnError ();
 }
 fclose (out);
 g_string_free (outBuffer, TRUE);
}

gchar GetHexChar (SCOUNTER num) {
 if (num < 10) return (num + '0');
 return ((num -10) + 'a');
}

void WriteInHex (gchar* str, SCOUNTER num) {

 str [0] = str [1] = str [2] = '\0';
 if (num > 255) return;
 str [0] = GetHexChar (num / 16);
 str [1] = GetHexChar (num % 16);
}
